Imports System.Collections
Imports System.Collections.Specialized
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Net
Imports CIPF

Namespace Annotations
  Public Class Util

    ''' <summary>
    ''' Combine 2 regions using the given mode.
    ''' </summary>
    ''' <param name="oCombinedRgn"></param>
    ''' <param name="oRgn"></param>
    ''' <param name="addMode"></param>
    ''' <remarks></remarks>
    Public Shared Sub CombineRegions(ByRef oCombinedRgn As Region, ByVal oRgn As Region, ByVal addMode As RegionAddMode)
      'Combine region with given region using the given mode. Used to combine annotations in a container to
      'one region. 
      If Not oRgn Is Nothing Then
        If oCombinedRgn Is Nothing Then
          oCombinedRgn = New Region
          oCombinedRgn.MakeEmpty()
        End If
        Select Case addMode
          Case RegionAddMode.Complement
            oCombinedRgn.Complement(oRgn)
          Case RegionAddMode.Intersect
            oCombinedRgn.Intersect(oRgn)
          Case RegionAddMode.Union
            oCombinedRgn.Union(oRgn)
          Case RegionAddMode.XorMode
            oCombinedRgn.Xor(oRgn)
        End Select
      End If
    End Sub

    ''' <summary>
    ''' Add rectangle together PROPERLY, not like the buggy .NET which treats empty regions as a rectangle at 0,0!!!!
    ''' </summary>
    ''' <param name="rectDst"></param>
    ''' <param name="rectSrc"></param>
    ''' <remarks>
    ''' </remarks>
    Public Shared Sub RectangleUnion(ByRef rectDst As Rectangle, ByVal rectSrc As Rectangle)
      '
      If rectDst.IsEmpty Then
        rectDst = rectSrc
      Else
        If Not rectSrc.IsEmpty Then
          rectDst = Rectangle.Union(rectDst, rectSrc)
        End If
      End If
    End Sub

    ''' <summary>
    ''' Transform a point from Image to Client coordinates using the given zoom and offset.
    ''' </summary>
    ''' <param name="objPt"></param>
    ''' <param name="sZoom"></param>
    ''' <param name="objOffset"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function ImageToClientCoordinates(ByVal objPt As PointF, _
                                                              ByVal sZoom As Single, _
                                                              ByVal objOffset As Point) As Point
      Return New Point(CInt(Math.Round((objPt.X - objOffset.X) * sZoom)), CInt(Math.Round((objPt.Y - objOffset.Y) * sZoom)))
    End Function

    ''' <summary>
    ''' Transform a rectangle from Image to Client coordinates using the given zoom and offset.
    ''' </summary>
    ''' <param name="objRect"></param>
    ''' <param name="sZoom"></param>
    ''' <param name="objOffset"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function ImageToClientCoordinates(ByVal objRect As Rectangle, _
                                                            ByVal sZoom As Single, _
                                                            ByVal objOffset As Point) As Rectangle
      Return New Rectangle(CInt(Math.Floor((objRect.X - objOffset.X) * sZoom)), _
                          CInt(Math.Floor((objRect.Y - objOffset.Y) * sZoom)), _
                          CInt(Math.Ceiling((objRect.Width * sZoom))), _
                          CInt(Math.Ceiling(objRect.Height * sZoom)))
    End Function

    ''' <summary>
    ''' Transform a rectangle from Image to Client coordinates using the given zoom and offset.
    ''' </summary>
    ''' <param name="objRect"></param>
    ''' <param name="sZoom"></param>
    ''' <param name="objOffset"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function ImageToClientCoordinates(ByVal objRect As RectangleF, _
                                                            ByVal sZoom As Single, _
                                                            ByVal objOffset As Point) As RectangleF
      Return New RectangleF((objRect.X - objOffset.X) * sZoom, (objRect.Y - objOffset.Y) * sZoom, _
                            (objRect.Width * sZoom), (objRect.Height * sZoom))
    End Function

    ''' <summary>
    ''' Transform a point from Client to Image coordinates using the given zoom and offset.
    ''' </summary>
    ''' <param name="objPt"></param>
    ''' <param name="sZoom"></param>
    ''' <param name="objOffset"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function ClientToImageCoordinates(ByVal objPt As Point, _
                                                              ByVal sZoom As Single, _
                                                              ByVal objOffset As Point) As PointF
      Return New PointF(objPt.X / sZoom + objOffset.X, objPt.Y / sZoom + objOffset.Y)
    End Function

    ''' <summary>
    ''' Transform a rectangle from Client to Image coordinates using the given zoom and offset.
    ''' </summary>
    ''' <param name="objRect"></param>
    ''' <param name="sZoom"></param>
    ''' <param name="objOffset"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function ClientToImageCoordinates(ByVal objRect As Rectangle, _
                                                              ByVal sZoom As Single, _
                                                              ByVal objOffset As Point) As RectangleF
      'Take the image offset and zoom into account ...
      Return New RectangleF(objRect.X / sZoom + objOffset.X, objRect.Y / sZoom + objOffset.Y, _
                          objRect.Width / sZoom, objRect.Height / sZoom)
    End Function

    ''' <summary>
    ''' Transform a rectangle from Client to Image coordinates using the given zoom and offset.
    ''' </summary>
    ''' <param name="objRect"></param>
    ''' <param name="sZoom"></param>
    ''' <param name="objOffset"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function ClientToImageCoordinates(ByVal objRect As RectangleF, _
                                                              ByVal sZoom As Single, _
                                                              ByVal objOffset As Point) As RectangleF
      'Take the image offset and zoom into account ...
      Return New RectangleF(objRect.X / sZoom + objOffset.X, objRect.Y / sZoom + objOffset.Y, _
                          objRect.Width / sZoom, objRect.Height / sZoom)
    End Function

    ''' <summary>
    ''' Create a rectangle from a point, given it size
    ''' </summary>
    ''' <param name="objPt"></param>
    ''' <param name="size "></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function PointToRectangle(ByVal objPt As Point, ByVal size As Integer) As Rectangle
      Dim objRect As Rectangle
      With objRect
        .X = objPt.X - size \ 2
        .Y = objPt.Y - size \ 2
        .Width = size
        .Height = size
      End With
      Return objRect
    End Function


    ''' <summary>
    ''' Create a rectangle from a point, given it size
    ''' </summary>
    ''' <param name="objPt"></param>
    ''' <param name="sRectSize"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function PointToRectangle(ByVal objPt As Point, ByVal sRectSize As Single) As RectangleF
      Dim objRect As RectangleF
      With objRect
        .X = objPt.X - sRectSize / 2
        .Y = objPt.Y - sRectSize / 2
        .Width = sRectSize
        .Height = sRectSize
      End With
      Return objRect
    End Function

    ''' <summary>
    ''' Create a rectangle from a point, given it size.
    ''' </summary>
    ''' <param name="objPt"></param>
    ''' <param name="sRectSize"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function PointToRectangle(ByVal objPt As PointF, ByVal sRectSize As Single) As RectangleF
      Dim objRect As RectangleF
      With objRect
        .X = objPt.X - sRectSize / 2
        .Y = objPt.Y - sRectSize / 2
        .Width = sRectSize
        .Height = sRectSize
      End With
      Return objRect
    End Function

    ''' <summary>
    ''' Create an array of rectangles from an array of points.
    ''' </summary>
    ''' <param name=" pts "></param>
    ''' <param name="rectSize "></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function PointToRectangle(ByVal pts As Generic.IList(Of Point), ByVal rectSize As Single) As RectangleF()
      'Create an array of rectangles, one for each point in the annotation
      Dim rect(pts.Count - 1) As RectangleF, index As Integer = 0
      For Each pt As Point In pts
        rect(index) = PointToRectangle(pt, rectSize)
        index += 1
      Next
      Return rect
    End Function

    ''' <summary>
    ''' Create an array of rectangles from an array of points.
    ''' </summary>
    ''' <param name="pts" ></param>
    ''' <param name="rectSize"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Overloads Shared Function PointToRectangle(ByVal pts As Generic.IList(Of PointF), ByVal rectSize As Single) As RectangleF()
      'Create an array of rectangles, one for each point in the annotation
      Dim rect(pts.Count - 1) As RectangleF, index As Integer = 0
      For Each pt As PointF In pts
        rect(index) = PointToRectangle(pt, rectSize)
        index += 1
      Next
      Return rect
    End Function

    ''' <summary>
    ''' Create a region from a graphics path, taking some exceptions into account.
    ''' </summary>
    ''' <param name="path"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GraphicsPathToRegion(ByVal path As GraphicsPath) As Region
      If path.PointCount > 1 Then
        Return New Region(path)
      Else
        Return Nothing
      End If
    End Function

    Friend Shared Function GetSVGText(ByVal oParent As Xml.XmlNode, ByVal strName As String) As String
      'return the text IF node exists!
      Dim oNode As Xml.XmlNode = oParent.Item(strName)
      If oNode Is Nothing Then
        Return ""
      Else
        Return oNode.InnerText
      End If
    End Function

    Friend Shared Function GetSVGTextFontSize(ByVal oParent As Xml.XmlNode, ByVal strName As String) As Integer
      'return the text IF node exists!
      Dim oNode As Xml.XmlNode = oParent.Item(strName)
      If oNode Is Nothing Then
        Return 0
      Else
        Return CInt(oNode.Attributes.GetNamedItem("font-size").Value)
      End If
    End Function

    Friend Shared Sub AddSVGText(ByVal SVGXMLFile As Xml.XmlWriter, _
                           ByVal strText As String, _
                           ByVal oPt As PointF, _
                           ByVal iFontSize As Integer, _
                           ByVal oColor As Color, _
                           ByVal numberFormat As System.Globalization.NumberFormatInfo)
      SVGXMLFile.WriteStartElement("text")
      SVGXMLFile.WriteAttributeString("x", oPt.X.ToString(numberFormat))
      SVGXMLFile.WriteAttributeString("y", oPt.Y.ToString(numberFormat))
      SVGXMLFile.WriteAttributeString("font-family", "Verdana")
      SVGXMLFile.WriteAttributeString("font-size", iFontSize.ToString)
      SVGXMLFile.WriteAttributeString("fill", ColorToWebColor(oColor))
      SVGXMLFile.WriteAttributeString("fill-opacity", "1")
      SVGXMLFile.WriteAttributeString("stroke", ColorToWebColor(oColor))
      SVGXMLFile.WriteString(strText)
      SVGXMLFile.WriteEndElement()
    End Sub

    Public Shared Function ColorToWebColor(ByVal oColor As Color) As String
      Dim strColor As String = Hex(oColor.ToArgb And &HFFFFFF)
      Do While strColor.Length < 6
        strColor = "00" & strColor
      Loop
      strColor = "#" & strColor
      Return strColor
    End Function

    Public Shared Function WebColorToColor(ByVal strColor As String) As Color
      strColor = "FF" & strColor.Substring(1)
      Dim iColor As Integer = Integer.Parse(strColor, System.Globalization.NumberStyles.HexNumber)
      Return Color.FromArgb(iColor)
    End Function

    Public Shared Function PointsToFloatPoints(ByVal points As Generic.IEnumerable(Of Point)) As Generic.IEnumerable(Of PointF)
      Dim floatPoints As New Generic.List(Of PointF)
      For Each pt As Point In points
        floatPoints.Add(New PointF(CSng(pt.X), CSng(pt.Y)))
      Next
      Return floatPoints
    End Function
  End Class

End Namespace